package com.logistics.utils.socket;
import com.baomidou.mybatisplus.extension.api.R;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.logistics.socket.model.RequestTaskModel;
import com.logistics.socket.model.ResponseSocketModel;
import com.logistics.socket.service.RequestSocketService;
import com.logistics.socket.service.ResponseSocketService;
import com.logistics.utils.configure.Configure;
import com.logistics.utils.spring.SpringContextHolder;
import com.logistics.utils.tool.StringUtils;
import com.logistics.utils.tool.UserUtils;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.Priority;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

@Log4j2
@Component
@ConditionalOnProperty(name = {"configure.rcsSocket"}, matchIfMissing = true)
public class WebSocketManagerClient extends WebSocketClient {

    private static final int HEARTBEAT_RATE = 1;

    // 连接失败重试
    private static final int RECONNECT_DELAY = 30;

    // 执行任务
    private static  ScheduledExecutorService executorService = null;

    private static  ScheduledFuture<?> scheduledFuture = null;

    private static RequestSocketService requestSocketService;

    private static ResponseSocketService responseSocketService;

    public WebSocketManagerClient(@Value("${configure.rcsSocketUrl}") String url) throws URISyntaxException {
        super(new URI(url));
        this.connect();
    }

    @Override
    public void onOpen(ServerHandshake serverHandshake) {
        // 调用心跳
        heart();
        // 取消重试
        if(StringUtils.isNotNull(scheduledFuture) && StringUtils.isNotNull(executorService)){
            scheduledFuture.cancel(false);
            executorService.shutdown();
        }
    }

    @Override
    public void onMessage(String msg) {
//        ResponseSocketModel response = StringUtils.stringToBena(msg, ResponseSocketModel.class);
//        if(response.getType().equals("5")){
//            System.out.println(msg);
//        }
//        System.out.println(msg);
        responseSocketService.responseMessage(msg);
    }

    @Override
    public void onClose(int i, String s, boolean b) {
        log.error("socket connection close");
        // 重新连接
        reconnectBlock();
    }

    @Override
    public void onError(Exception e) {
        log.error("socket connection error", e);
    }

    /**
     * 重新连接
     */
    private void reconnectBlock(){
        executorService = Executors.newScheduledThreadPool(1);
        Runnable task = () -> {
            try {
                this.reconnectBlocking();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        };
        scheduledFuture = executorService.scheduleAtFixedRate(task, RECONNECT_DELAY, RECONNECT_DELAY, TimeUnit.SECONDS);
    }

    private void heart(){
        Runnable task = () -> {
            try {
                EventData<RequestTaskModel> request = EventData.build("__heart", null);
                requestSocketService.sendMessage(request);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        };
        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
        executorService.scheduleAtFixedRate(task, 1, HEARTBEAT_RATE, TimeUnit.SECONDS);
    }

    @Autowired
    @Lazy
    public void setRequestSocketService(RequestSocketService requestSocketService) {
        this.requestSocketService = requestSocketService;
    }

    @Autowired
    @Lazy
    public void setResponseSocketService(ResponseSocketService responseSocketService){
        this.responseSocketService = responseSocketService;
    }

}
